home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1995 April / Internet Tools.iso / ip / ppp / mac / macppp2.0.1-src.hqx / MacPPP 2.0.1 src / io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-28  |  22.3 KB  |  850 lines

  1. /*  io.c
  2.  *    I/O routines for MacPPP
  3.  *
  4.  * Copyright 1992-1993 Merit Network, Inc. and The Regents of the
  5.  *  University of Michigan.  Usage of this source code is restricted
  6.  *  to non-profit, non-commercial purposes.  The source is provided
  7.  *  "as-is", without warranty.
  8.  */
  9. #include "ppp.h"
  10.  
  11. /* macro to calculate new fcs */
  12. #define pppfcs(fcs, c)        ((fcs >> 8) ^ lap->fcstab[(fcs ^ c) & 0x00ff])
  13.  
  14. /*
  15. *    Pass the completed IP packet up to the IP layer.
  16. */
  17. void    rcvip(register LapInfo *lap, struct bufheader *bufptr)
  18. {
  19. long        oldA5;
  20.  
  21.     if (lap->rds.rdsparm.lnb.lnb_ptr != nil) { /* MacTCP doesn't always call ReadRest */
  22.         /* DebugStr("\pIPPH not ready"); */
  23.         release((struct bufheader *)lap->rds.rdsparm.lnb.lnb_ptr);    /* free un-copied data */
  24.     }
  25.     
  26.     lap->idle_timer = 0;    /* clear idle timer */
  27.     tcp_window_fix(lap, bufptr);    /* TCP window hack */
  28.     
  29.     lap->rds.laphdr.ptr = nil;
  30.     lap->rds.laphdr.length = 0;
  31.     lap->rds.lapBroadcast = FALSE;
  32.     lap->rds.lap = lap;
  33.     lap->rds.ph_rp = (ProcPtr) readpkt;    /* set up ptr's to */
  34.     lap->rds.ph_rr = (ProcPtr) readrest;    /* mysterious rtn's */
  35.     lap->rds.rdsparm.lnb.lnb_ptr = (b_8 *) bufptr;    /* ptr to packet */
  36.     lap->rds.ph_bytesleft =  bufptr->length;    /* length of packet */
  37.  
  38.     /* pass pkt to IP layer in a rdStruct */
  39.     if (lap->ip_ph != nil) {
  40.         oldA5 = seta5((long)lap->ipGlobals);    /* setup apps A5 */
  41.         (*(lap->ip_ph))(&(lap->rds));
  42.         seta5(oldA5);                    /* restore old A5 */
  43.     } else
  44.         PPP_DEBUG_CHECKS("\pNo ip_ph to call!");
  45. }
  46.  
  47. OSErr    readpkt(struct rdStruct *rds, Ptr bufp, long buflen)
  48. {
  49. #ifdef LOG
  50.     log(GetLAPPtr(),0x3, (int) TickCount(),(int)( rds->rdsparm.lnb.lnb_ptr), (int) buflen);
  51. #endif
  52.     /* 
  53.     *    It's against the rules to have ReadPacket read in the remainder
  54.     *    of the packet. You have to call ReadRest for that 
  55.     *    Too bad nobody plays by the rules. ReadPacket can't return an error
  56.     *    if bytesleft exactly equals buflen, or else the higher layer gets
  57.     *    an error on a packet with 0 bytes of data, which breaks everything.
  58.     */
  59.     if (rds->ph_bytesleft >= buflen) {    /* will this buffer fill up? */
  60.         yankbuf((struct bufheader *)rds->rdsparm.lnb.lnb_ptr, 
  61.             (b_8 *) bufp,(short) buflen);    /* copy data */
  62.         rds->ph_bytesleft -= buflen;    /* update len */
  63.         return    (0);        /* buffer has data */
  64.     }
  65.     return (-1);        /* call ReadRest instead */
  66. }
  67. /*
  68. *    ReadRest is called to read the remainder of a packet.  It must be 
  69. *    called exactly once per packet.
  70. */
  71. long    readrest(register struct rdStruct *rds, Ptr bufp, long buflen)
  72. {
  73.     long     rc;
  74. #ifdef LOG
  75.     log(GetLAPPtr(),0x4, (int) TickCount(),(int)( rds->rdsparm.lnb.lnb_ptr), (int) buflen);
  76. #endif
  77.     if (rds->ph_bytesleft > buflen) {    /* packet won't fit Truncate */
  78.         yankbuf((struct bufheader *)rds->rdsparm.lnb.lnb_ptr, 
  79.          (b_8 *) bufp, (short) buflen);
  80.         rds->ph_bytesleft -= buflen;    /* update # of bytes truncated */
  81.         rc = -(rds->ph_bytesleft);
  82.     } else {
  83.         yankbuf((struct bufheader *)rds->rdsparm.lnb.lnb_ptr,
  84.             (b_8 *) bufp, (short) rds->ph_bytesleft);
  85.         rc = buflen - rds->ph_bytesleft;
  86.         rds->ph_bytesleft = 0;    /* the entire packet is copied */
  87.     }
  88.     release((struct bufheader *) rds->rdsparm.lnb.lnb_ptr);
  89.     rds->rdsparm.lnb.lnb_ptr = (b_8 *) nil;
  90.     return rc;    /* return value */
  91. }
  92.  
  93. /*
  94.  * ProcFrame - process a PPP frame in an MBUF
  95.  */
  96.  
  97. void
  98. ProcFrame(register LapInfo *lap, register struct bufheader *bufptr)
  99. {
  100.     register b_16    proto;
  101.     register short    RecvByte;
  102.     
  103.     /* pull off header */
  104.     if ((RecvByte = yankbyte(bufptr)) < 0)
  105.         goto error;
  106.  
  107.     if (RecvByte == HDLC_ALL_ADDR) {
  108.         if ((RecvByte = yankbyte(bufptr)) < 0)
  109.             goto error;
  110.  
  111.         if (RecvByte == HDLC_UI) {
  112.             if ((RecvByte = yankbyte(bufptr)) < 0)
  113.                 goto error;
  114.  
  115.             if ((RecvByte & 0x01) != 0) {
  116.                 proto = RecvByte;
  117.             } else {
  118.                 proto = RecvByte << 8;
  119.  
  120.                 if ((RecvByte = yankbyte(bufptr)) < 0)
  121.                     goto no_error;
  122.  
  123.                 if ((RecvByte & 0x01) == 0)
  124.                     goto error;
  125.  
  126.                 proto += RecvByte;
  127.             }
  128.         } else {
  129.             goto error;
  130.         }
  131.     } else {
  132.         if (RecvByte & 0x01) {
  133.             proto = RecvByte;
  134.         } else {
  135.             proto = RecvByte << 8;
  136.  
  137.             if ((RecvByte = yankbyte(bufptr)) < 0)
  138.                 goto no_error;
  139.  
  140.             proto += RecvByte;
  141.         }
  142.     }
  143.  
  144.     /* handle frame */
  145.  
  146.     switch (proto) {
  147.     case PPP_IP_PROTOCOL:
  148.         if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
  149.             PPP_DEBUG_CHECKS("\pnot open for IP traffic");
  150.             goto in_error;
  151.         }
  152.         rcvip(lap, bufptr);
  153.         break;
  154.  
  155.     case PPP_VJ_COMP_PROTOCOL:
  156.         if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
  157.             PPP_DEBUG_CHECKS("\pnot open for Compressed TCP/IP traffic");
  158.             goto in_error;
  159.         }
  160.         if (!(lap->ipcp_i.local.work_negotiate & IPCP_N_COMPRESS)) {
  161.             PPP_DEBUG_CHECKS("\pCompressed TCP/IP not enabled");
  162.             goto in_error;
  163.         }
  164.         if (slhc_uncompress(lap, bufptr) <= 0) {
  165.             PPP_DEBUG_CHECKS("\pCompressed TCP/IP packet error");
  166.             goto in_error;
  167.         }
  168.         rcvip(lap, bufptr);
  169.         break;
  170.  
  171.     case PPP_VJ_UNCOMP_PROTOCOL:
  172.         if (lap->ppp_fsm[IPcp].state != fsmOPENED) {
  173.             PPP_DEBUG_CHECKS("\pnot open for Uncompressed TCP/IP traffic");
  174.             goto in_error;
  175.         }
  176.         if (!(lap->ipcp_i.local.work_negotiate & IPCP_N_COMPRESS)) {
  177.             PPP_DEBUG_CHECKS("\pUncompressed TCP/IP not enabled");
  178.             goto in_error;
  179.         }
  180.         if (slhc_remember(lap, bufptr) <= 0) {
  181.             PPP_DEBUG_CHECKS("\pUncompressed TCP/IP packet error");
  182.             goto in_error;
  183.         }
  184.         rcvip(lap, bufptr);
  185.         break;
  186.  
  187.     case PPP_LCP_PROTOCOL:
  188.         fsm_proc(&(lap->ppp_fsm[Lcp]), bufptr);
  189.         break;
  190.  
  191.     case PPP_PAP_PROTOCOL:
  192.         if (lap->ppp_phase != pppAUTHENTICATE
  193.             && lap->ppp_phase != pppNETWORK) {
  194.             PPP_DEBUG_CHECKS("\pNot ready for Authentication");
  195.             goto in_error;
  196.         }
  197.         pap_proc(&(lap->ppp_fsm[Pap]), bufptr);
  198.         break;
  199.  
  200.     case PPP_IPCP_PROTOCOL:
  201.         if (lap->ppp_phase != pppNETWORK) {
  202.             PPP_DEBUG_CHECKS("\pNot ready for IPCP traffic");
  203.             goto in_error;
  204.         }
  205.         fsm_proc(&(lap->ppp_fsm[IPcp]), bufptr);
  206.         break;
  207.  
  208.     default:
  209.         lap->InUnknown++;                /* count unknown protocol */
  210.         if (lap->ppp_fsm[Lcp].state == fsmOPENED) {
  211.             makeroom(bufptr, 2);
  212.             put16(bufptr->dataptr, proto);        /* put protocol field back on */
  213.             fsm_send(&(lap->ppp_fsm[Lcp]), PROT_REJ, 0, bufptr); /* send protocol reject */
  214.         } else    
  215.             release(bufptr);
  216.         break;
  217.     }
  218.     return;
  219.  
  220.     /* finish up */
  221. in_error:
  222.     lap->InError++;
  223.     goto no_error;
  224. error:
  225.     lap->InHeader++;
  226.     PPP_DEBUG_CHECKS("\pPPP header error");
  227. no_error:
  228.     release(bufptr);        /* release the buffer */
  229.     return;
  230. }
  231.  
  232. long
  233. GetQSize(register LapInfo *lap) {
  234.     register long qcount;
  235.  
  236.     lap->stat_pb.csCode = 2;        /* call SerGetBuf routine */
  237.     PBStatusImmed((ParmBlkPtr) &lap->stat_pb);
  238.     qcount =  *( (long *) lap->stat_pb.csParam);
  239.     if (qcount > RXBUFSIZE)
  240.         qcount = RXBUFSIZE;
  241.     lap->r_iopb.iop.ioReqCount = qcount;
  242.     return qcount;
  243. }
  244.  
  245. void RcvDeferred(void)
  246. {
  247.     asm {
  248.         lea OFFSET(LapInfo, r_iopb.iop)(a1),a0
  249.         _PBRead    ASYNC                /* read the data */
  250.     }
  251. }
  252.  
  253. void
  254. ProcRcvPPP(void){
  255.  
  256.     register LapInfo    *lap;
  257.     register long        qcount;
  258.     struct TMprocess    *tmprocp;
  259.  
  260.     asm {
  261.         move.l    a1,tmprocp
  262.     }
  263.     lap = tmprocp->tmsavptr.lap;
  264.     if (GetQSize(lap) == 0)
  265.         PrimeTime( (QElemPtr) &lap->rxp_task, 4L); /* no data, try again in 4 ms */
  266.     else {
  267.         if (lap->HasDeferredTasks)
  268.             DTInstall((QElemPtr) &lap->defer_rx);
  269.         else
  270.             PBReadAsync((ParmBlkPtr) &lap->r_iopb.iop);
  271.     }
  272. }
  273.  
  274. #define RXHILIMIT 32 /* Hi-water mark for Reading data immediately */
  275. void
  276. SerReadDone(void){
  277.  
  278.     typedef enum
  279.     {
  280.         c_Flag,            /* PPP opening/closing flag */
  281.         c_Escape,        /* PPP escape char */
  282.         c_Normal,        /* A normal data character */
  283.         c_Ignore,        /* Character to be ignored */
  284.         c_Error            /* Errored char received */
  285.     }    class_t;
  286.  
  287.     register LapInfo    *lap;
  288.     sdiopb        *pb;
  289.     struct bufheader    *tempbuf;
  290.     register    short        *cntptr;
  291.     b_8                    *dataptr;
  292.     register    b_8        *rbufptr;
  293.     register    b_8        *rbufend;
  294.     register class_t    RecvClass;
  295.     register b_8        RecvByte;
  296.     register HDLCState    RecvState;
  297.     register b_8        StatusByte;
  298.     long                qcount;
  299.     OSErr                rc;
  300.     
  301.     asm {
  302.         move.l a0,pb             ; set up paramblkptr
  303.     };
  304.     
  305.     lap = pb->lap;
  306.  
  307.     if ((rc = pb->iop.ioResult) != noErr) {
  308.         lap->readerr++;
  309.         lap->lasterr = rc;
  310.         PPP_DEBUG_CHECKS("\pSerial driver rx. error");
  311.         goto rcvexit;
  312.     }
  313.     qcount = pb->iop.ioActCount;
  314.  
  315.     lap->InRxOctetCount += qcount;        /* count the octets */
  316.     rbufptr = lap->rxbuf;
  317.     rbufend = rbufptr + qcount;
  318.     dataptr = lap->bufptr->dataptr;        /* pointer to start of data in mbuf */
  319.     cntptr = &(lap->bufptr->length);
  320.     while (rbufptr < rbufend) {
  321.         RecvByte = *rbufptr++;
  322.         RecvState = lap->read_state;
  323.  
  324.         if (lap->bufptr == nil) {
  325.             if ( (lap->bufptr = getbuffer() ) != nil ) {
  326.                 dataptr = lap->rddata = lap->bufptr->dataptr;
  327.                 cntptr = &(lap->bufptr->length);
  328.             } else {
  329.                 PPP_DEBUG_CHECKS("\pNo rbufs");
  330.                 goto rcvexit;
  331.             }
  332.         }
  333.         /* figure equivalence class of input char/err */
  334.         if (RecvByte == PPP_FLAG)
  335.             RecvClass = c_Flag;
  336.         else if (RecvByte == PPP_ESCAPE)
  337.             RecvClass = c_Escape;
  338.         else if ((RecvByte & 0xE0) != 0)
  339.             RecvClass = c_Normal;
  340.         else {
  341.             if (((1L << RecvByte) & lap->PPP_RecvACM) != 0) {
  342.                 RecvClass = c_Ignore;
  343.             } else
  344.                 RecvClass = c_Normal;
  345.         }
  346.  
  347.         /*
  348.          * "I feel the need, the need for speed" The C switch()
  349.          * statement is too slow for use here, so we just use a
  350.          * carefully organized if...elseif...elseif... statement to
  351.          * optimize this routine for speed.  --ejs
  352.          */
  353.         /* handle receive states
  354.          * Taken from KA9Q and re-arranged for better performance
  355.          * also changed to if else style per ejs suggestion.  --ljb
  356.          */
  357.         if (RecvState == s_Data) {
  358.             if (RecvClass == c_Normal) {
  359.                 if ((*cntptr)++ <= PPP_BUFSIZE) {
  360.                     lap->RecvFCS = pppfcs(lap->RecvFCS, RecvByte);
  361.                     *(lap->rddata)++ = RecvByte;
  362.                 } else {
  363.                     (*cntptr)--;
  364.                     lap->InFrameOvr++;
  365.                     lap->read_state = s_Idle;
  366.                 }
  367.             }
  368.             else if (RecvClass == c_Escape)
  369.                 lap->read_state = s_Escape;
  370.             else if (RecvClass == c_Flag) {
  371.                 if (lap->RecvFCS == FCS_TERM) {
  372.                     lap->RecvFCS = FCS_INIT;  /* reset FCS */
  373.                     lap->InOpenFlag++;        /* count good frame */
  374.                     tempbuf = lap->bufptr;        /* get pointer to current mbuf */
  375.                                             /* must make copy due to possible re-entrancy */
  376.                     lap->bufptr = nil;        /* need new buffer next time */
  377.                     tempbuf->length -= 2;        /* trim FCS bytes */
  378.                     ProcFrame(lap, tempbuf);    /* process the PPP frame */
  379.                 } else if (*cntptr > 0) {
  380.                     PPP_DEBUG_CHECKS("\pGot a bad FCS");
  381.                     lap->InCheckSeq++;
  382.                     slhc_toss(&lap->comp);    /* let VJ compression engine know */
  383.                     *cntptr = 0;
  384.                     lap->rddata = dataptr;
  385.                     lap->RecvFCS = FCS_INIT;
  386.                     lap->stat_pb.csCode = 8;        /* call SerStatus routine */
  387.                     PBStatusImmed((ParmBlkPtr) &lap->stat_pb);
  388.                     StatusByte = *( (b_8 *) lap->stat_pb.csParam);
  389.                     if (StatusByte & swOverrunErr)
  390.                         lap->InSoftOvr++;
  391.                     if (StatusByte & hwOverrunErr)
  392.                         lap->InHardOvr++;
  393.                     if (StatusByte & framingErr)
  394.                         lap->InFramingErr++;
  395.                 }
  396.             }
  397.         }
  398.         else if (RecvState == s_Escape) {
  399.             if (RecvClass == c_Normal) {
  400.                 if (*cntptr <= PPP_BUFSIZE) {
  401.                     RecvByte ^= 0x20;
  402.                     lap->RecvFCS = pppfcs(lap->RecvFCS, RecvByte);
  403.                     *(lap->rddata)++ = RecvByte;
  404.                     (*cntptr)++;
  405.                     lap->read_state = s_Data;
  406.                 } else {
  407.                     lap->InFrameOvr++;
  408.                     lap->read_state = s_Idle;
  409.                 }
  410.             }
  411.             else if (RecvClass == c_Flag)
  412.                 lap->read_state = s_Idle;
  413.         }
  414.         else if (RecvState == s_Idle) {
  415.             if (RecvClass == c_Flag) {
  416.                 lap->RecvFCS = FCS_INIT;
  417.                 lap->read_state = s_Data;
  418.                 lap->rddata = dataptr;
  419.                 *cntptr = 0;
  420.             } else 
  421.                 lap->InIdleToss++;
  422.         }
  423.         else if (RecvState == s_Init) {
  424.             RecvByte &= 0x7f;        /* clear high bit */
  425.             if (!lap->term_mode || ( RecvByte != 0x0a && RecvByte != 0x08) ) {
  426.                 if (*cntptr >= PPP_BUFSIZE) {
  427.                     lap->rddata = dataptr;    /* wrap around */
  428.                     *cntptr = 0;
  429.                 }
  430.                 *(lap->rddata)++ = RecvByte;    /* buffer and hi bit */
  431.                 (*cntptr)++;
  432.             } else if (RecvByte == 0x08 && *cntptr > 0) {
  433.                 (*cntptr)--;    /* decrement counter */
  434.                 lap->rddata--;    /* decrement pointer */
  435.             }
  436.         }
  437.     }
  438.     
  439. rcvexit:
  440.     if (GetQSize(lap) > RXHILIMIT) {
  441.         PrimeTime( (QElemPtr) &lap->rxp_task, 0L);
  442.     }
  443.     else
  444.         PrimeTime( (QElemPtr) &lap->rxp_task, 2L);
  445.  
  446. }
  447.  
  448. /* queue a frame to transmitted */
  449. OSErr QueueFrame (LapInfo *lap, struct bufheader *bufptr, struct ipbuf *ipbp)
  450. {
  451.     PPPiopb    *pb;
  452.     
  453.        /* try to get a free transmit queue element */
  454.     
  455.     if ((pb = (PPPiopb *)lap->pppbq.qHead) != nil) {
  456.         Dequeue( (QElemPtr) pb, (QHdrPtr) &lap->pppbq);
  457.     }
  458.     if (pb != nil) {
  459.         if ((pb->ipbuf = ipbp) != nil) {    /* check if from MacTCP */
  460. #ifdef LOG
  461.     log(lap, 0x1,(int) TickCount(),(int) ipbp, (int)ipbp->iop.ioCompletion );
  462. #endif
  463.             ipbp->iop.ioResult = inProgress; /* mark i/o as async */
  464.         }
  465.         pb->bufptr = bufptr;                /* point to mbuf (if available) */
  466.         Enqueue((QElemPtr) pb, (QHdrPtr) &lap->out_q);        /* queue for xmit */
  467.     } else {
  468.         /* we're out of Q elements (very bad) */
  469.         lap->outofiopbs++;
  470.         PPP_DEBUG_CHECKS("\pOut of ioParam blocks");
  471.         IOCompleted(lap, ipbp);
  472.         return(noErr);
  473.     }
  474.             
  475.     /* Prime transmitter (if needed) */
  476.     if (lap->needTxPrime) {
  477.         lap->needTxPrime = false;
  478.         ProcXmtPPP(lap);        /* start transmitter */
  479.     }
  480.  
  481.     return(noErr);
  482. }
  483.  
  484. void IOCompleted(LapInfo *lap, struct ipbuf *ipbp)
  485. {
  486. long    oldA5;
  487.  
  488. #ifdef LOG
  489.     log(lap, 0x2, (int) TickCount(), (int) ipbp, 0);
  490. #endif
  491.     
  492.     if (ipbp->iop.ioCompletion != nil) {    /* check if completion routine */
  493.         oldA5 = seta5((long)lap->ipGlobals);
  494.         ipbp->iop.ioResult = noErr;    /* always return no error */
  495.         asm {
  496.             movea.l    ipbp,a0        /* set pointer to iop */
  497.             move.l    noErr,d0    /* result code */
  498.             move.l    a0,-(a7)
  499.             movea.l    IOParam.ioCompletion(a0),a1    /* completion routine*/
  500.             tst.w    d0
  501.             jsr        (a1)
  502.             addq.l    #4,a7
  503.         }
  504.         seta5(oldA5);
  505.     }
  506. }
  507.  
  508. void IOfinish(register LapInfo *lap, PPPiopb *pb)
  509. {
  510.     struct ipbuf *ipbp = pb->ipbuf;
  511.  
  512.     Enqueue( (QElemPtr) pb, (QHdrPtr) &lap->pppbq);    /* give back iopb to pool */
  513.     IOCompleted(lap, ipbp);        /* call the completion routine */
  514. }
  515.  
  516. PPPiopb *Getxmitpb(LapInfo *lap)
  517. {
  518.     PPPiopb                *pb;
  519.     struct bufheader    *bufptr;
  520.     struct ipbuf        *ipb;
  521.     struct wdsEntry        *wdsp;
  522.     b_8                    *datap;
  523.     short                n, protocol = PPP_IP_PROTOCOL;
  524.     b_16                proto;
  525.     
  526.     if ((pb = (PPPiopb *)lap->out_q.qHead) != nil)
  527.         Dequeue( (QElemPtr) pb, (QHdrPtr) &lap->out_q);    /* Dequeue a xmit buffer */
  528.     else
  529.         return nil;
  530.  
  531.     if    (pb->bufptr != nil)    {    /* check if from MacTCP or LAP */
  532.         if (pb->ipbuf != nil) { /* special case for LCP echos */
  533.             pb->ipbuf = nil;
  534.             if ((bufptr = getbuffer()) == nil)    /* get a buffer */
  535.                 return nil;
  536.             bufptr->length = pb->bufptr->length;
  537.             BlockMove(pb->bufptr->dataptr, bufptr->dataptr, (long) bufptr->length);
  538.             pb->bufptr = bufptr;
  539.             /* prime lcp echo routine */
  540.             PrimeTime((QElemPtr)&lap->echo_task, (long)lap->prefdata.echo * 1000L);
  541.             return pb;
  542.         }
  543.     } else {
  544.         if ((ipb = pb->ipbuf) == nil) {    /* shouldn't happen */
  545.             PPP_DEBUG_CHECKS("\pip buffer ptr nil");
  546.             return nil;
  547.         }
  548.         
  549.         if ((bufptr = getbuffer()) == nil){    /* get a buffer */
  550.             IOfinish(lap, pb);
  551.             return nil;
  552.         }
  553.         wdsp = &(ipb->ip);        /* point to wds entries (@ip header) */
  554.         datap = bufptr->dataptr;
  555.  
  556.         /* copy packet into a buffer */
  557.     
  558.         while ( (n = wdsp->length) != 0 ) {
  559.             BlockMove(wdsp->ptr, datap, (long) n);
  560.             bufptr->length += n;
  561.             datap += n;
  562.             wdsp++;
  563.         }
  564.         tcp_window_fix(lap, bufptr);    /* chop down TCP window size */
  565.  
  566.         if (lap->ipcp_i.remote.work_negotiate & IPCP_N_COMPRESS) {
  567.             /* Attempt IP/TCP header compression */
  568.             switch (slhc_compress(lap, bufptr,
  569.                          lap->ipcp_i.remote.work.ipcp_option.slot_compress)) {
  570.             case SL_TYPE_IP:
  571.                 protocol = PPP_IP_PROTOCOL;
  572.                 break;
  573.             case SL_TYPE_COMPRESSED_TCP:
  574.                 protocol = PPP_COMPR_PROTOCOL;
  575.                 break;
  576.             case SL_TYPE_UNCOMPRESSED_TCP:
  577.                 protocol = PPP_UNCOMP_PROTOCOL;
  578.                 break;
  579.             default:
  580.                 lap->OutError++;
  581.                 PPP_DEBUG_CHECKS("\pVJ compress error");
  582.                 release(bufptr);
  583.                 IOfinish(lap, pb);
  584.                 return nil;
  585.             }
  586.         }
  587.         if (lap->ppp_phase == pppDEAD) {
  588.             lap->OutError++;
  589.             PPP_DEBUG_CHECKS("\pDead link output error");
  590.             release(bufptr);
  591.             IOfinish(lap, pb);
  592.             return nil;
  593.         }
  594.  
  595.         htonppp(lap, protocol, bufptr);
  596.         pb->bufptr = bufptr;
  597.     }
  598.     return pb;        /* pointer to transmit iopb */
  599. }
  600.  
  601. /* routine to transmit some characters from the transmit fifo
  602.  * This is executed as part of the transmit IO completion routine.
  603.  * TXBUFSIZE controls the maximum number of characters to transmit.
  604.  * Don't make this too large as it may result in receive overruns
  605.  * because this will often be executed during level 2 interrupt time.
  606.  */
  607. void    xmitout(register LapInfo *lap)
  608. {
  609.     register unsigned short maxsend;
  610.     register ioParam *iop = &(lap->w_iopb.iop);
  611.     
  612.     if (lap->ok_to_xmit && (lap->XmitQSize > 0)) {
  613.         lap->ok_to_xmit = false;
  614.         if ( (maxsend = XMITQLEN - lap->XmitQHead) > MAXXMIT)
  615.             maxsend = MAXXMIT;
  616.         iop->ioReqCount = lap->XmitQSize > maxsend ? maxsend : lap->XmitQSize;
  617.         iop->ioBuffer = (Ptr) &lap->XmitQ[lap->XmitQHead];
  618.         asm {
  619.             movea.l iop, a0
  620.             _PBWrite    ASYNC
  621.         }
  622.     }
  623. }
  624.  
  625. /* routine to place some chars in the transmit fifo */
  626. void    xmitfifo(register LapInfo *lap, short len)
  627. {
  628.     short    i;
  629.     register Byte    *bufptr = lap->xbuf;
  630.     
  631.     for    ( i = 0 ; i < len ; ++i ) {
  632.         if (lap->XmitQSize >= XMITQLEN) {
  633.             PPP_DEBUG_CHECKS("\pOverflowed xmit fifo");    /* this shouldn't happen */
  634.             break;            
  635.         }
  636.         lap->XmitQ[lap->XmitQTail++] = *bufptr++;
  637.         lap->XmitQTail &= (XMITQLEN - 1);
  638.         lap->XmitQSize++;
  639.     }
  640.     xmitout(lap);            /* try to xmit some characters in the fifo */
  641. }
  642.  
  643. void TxCDeferred(void)
  644. {
  645. LapInfo *lap;
  646.  
  647.     asm {
  648.         move.l a1,lap
  649.     }
  650.     lap->ok_to_xmit = true;        /* okay to transmit some more */
  651.     xmitout(lap);     /* transmit some more bytes */
  652. }
  653.  
  654. /*
  655. *    This is the serial write i/o completion routine.  All it does is call
  656. *    the xmitout routine to transmit some chars from the fifo.
  657. */
  658. ProcPtr hdlcwioc()
  659. {
  660. register LapInfo *lap;
  661. sdiopb        *pb;
  662. register    unsigned short count;
  663.  
  664.     /*  We are allowed to trash a0,a1,d0-d2 */
  665.     asm {
  666.         move.l a0,pb             ; set up paramblkptr
  667.         };
  668.     
  669.     lap = pb->lap;
  670.  
  671.     count = pb->iop.ioActCount;
  672.  
  673.     if (count > pb->iop.ioReqCount) {
  674.         lap->writerr++;
  675.         PPP_DEBUG_CHECKS("\pwrite: Tx berserk");
  676.     }
  677.         
  678.     if (pb->iop.ioResult != noErr) {
  679.         if (pb->iop.ioResult == abortErr) {
  680.             lap->XmitQSize = lap->XmitQHead = lap->XmitQTail = 0;
  681.             lap->ok_to_xmit = true;
  682.             return;
  683.         }
  684.         lap->writerr++;    /* count bad writes */
  685.     }
  686.  
  687.     lap->OutTxOctetCount += count;    /* add to total out count */
  688.     lap->XmitQSize -= count;
  689.     if ( (lap->XmitQHead += count) >= XMITQLEN)
  690.         lap->XmitQHead = 0;
  691.  
  692.     if (lap->HasDeferredTasks)
  693.         DTInstall((QElemPtr) &lap->defer_txcomplete);
  694.     else {
  695.         lap->ok_to_xmit = true;
  696.         xmitout(lap);
  697.     }
  698. }
  699.  
  700. void XmtDeferred(void)
  701. {
  702. LapInfo *lap;
  703.  
  704.     asm {
  705.         move.l a1,lap
  706.     }
  707.     ProcXmtPPP(lap);
  708. }
  709.  
  710. /* time manager routine to re-start transmitter */
  711. void    XmtTMProc(void)
  712. {
  713. LapInfo *lap;
  714. struct TMprocess    *tmprocp;
  715.  
  716.     asm    {
  717.         move.l    a1,tmprocp
  718.     };
  719.     lap = tmprocp->tmsavptr.lap;
  720.     if (lap->HasDeferredTasks)
  721.         DTInstall((QElemPtr) &lap->defer_tx);
  722.     else
  723.         ProcXmtPPP(lap);
  724. }
  725.  
  726. void    ProcXmtPPP(register LapInfo *lap)
  727. {
  728. register short        XmitByte;
  729. short                sreg;
  730. ProcPtr                ioc;
  731. register HDLCState    wstate;
  732. PPPiopb                *pb;
  733. register b_8        *xbufp;
  734.  
  735.     /* we loop through this routine until either it is done handling the
  736.     output or the xmit fifo is too full. In the latter case, we re-prime the
  737.     routine to execute later (when there will be more room in the fifo)
  738.     */
  739.     while (TRUE) {
  740.         if ( lap->XmitQSize > (XMITQLEN - 8) ) {
  741.             if (!(lap->txp_task.atm.qType & TASK_QUEUED))    /* check if task in q */
  742.                 PrimeTime((QElemPtr) &lap->txp_task, 16L);
  743.             break;
  744.         }
  745.  
  746.         wstate = lap->write_state;    /* put in register for speed */
  747.         xbufp = lap->xbuf;
  748.         if (wstate == s_Data) {    /* we're in the middle of a packet */
  749.             if ((XmitByte = yankbyte(lap->active->bufptr)) == -1 ) {/* get byte */
  750.                 lap->write_state = s_SendFCS;    /* move to FCS state */
  751.                 release(lap->active->bufptr);
  752.                 lap->active->bufptr = nil;
  753.             } else {
  754.                 lap->XmitFCS = pppfcs(lap->XmitFCS, XmitByte);
  755.                 /* escape ESC, FLAG, and all characters in escape map */
  756.                    if (((XmitByte < 0x20) && (lap->PPP_activeACM & (1L << XmitByte)))
  757.                   ||  (XmitByte == PPP_FLAG) || (XmitByte == PPP_ESCAPE)) {
  758.                     *xbufp++ = PPP_ESCAPE;    /* send ESC */
  759.                       XmitByte ^= 0x20;    /* encoded character */
  760.                 }
  761.                 *xbufp++ = (Byte) XmitByte;   /* un-escaped character */
  762.                 xmitfifo(lap, xbufp - lap->xbuf);    /* fifo the data */
  763.             }
  764.         } else if (wstate == s_Idle) {        /* just sitting around */
  765.             if ((lap->active = Getxmitpb(lap)) != nil) {
  766.                 /* something on queue */
  767.                 if (lap->active->ipbuf == nil) /* escape LCP, NCP's for safety */
  768.                     lap->PPP_activeACM = 0xFFFFFFFFL;
  769.                 else {
  770.                     /* check for packet sent to our IP address */
  771.                     if (lap->cur_ip_addr ==
  772.                         get32((b_8 *)lap->active->ipbuf->ip.ptr + IP_DEST_OFFSET)) {
  773.                             lap->write_state = s_Loopback;
  774.                             /* need exclusivity from  receiver */
  775.                             PrimeTime((QElemPtr) &lap->txp_task, 0L);
  776.                             break;
  777.                     }
  778.                     lap->PPP_activeACM = lap->PPP_XmitACM; /* use current ACCM */
  779.  
  780.                 }
  781.                 lap->write_state = s_Data;
  782.                 lap->OutOpenFlag++;        /* about to send an open flag */
  783.                 lap->XmitFCS = FCS_INIT;    /* start new FCS calculation */
  784.                 if (lap->ok_to_xmit) { /* see if already xmitting */
  785.                     *xbufp = PPP_FLAG; /* no, so send a flag */
  786.                     xmitfifo(lap, 1); 
  787.                 }
  788.             } else {
  789.                 sreg = set_sr(0x2300);    /* disable ints */
  790.                 /* possible for another datagram to have been added */
  791.                 if (lap->out_q.qHead != nil) {
  792.                     set_sr(sreg);
  793.                     continue;
  794.                 } else {
  795.                     lap->needTxPrime = true;
  796.                     set_sr(sreg);
  797.                     break;
  798.                 }
  799.             }
  800.         } else if (wstate == s_SendFCS) {     /* Packet is done */
  801.             lap->write_state = s_Finish;    /* done with pkt  */
  802.  
  803.         /* The FCS is complemented before transmitting.  It is also
  804.         *  transmitted low byte first, then high byte, which is a real
  805.         *  pain in the butt.
  806.         */
  807.             lap->XmitFCS ^= 0xffff;        /* send one's compl. */
  808.             XmitByte = lap->XmitFCS & 0xFF;
  809.             wstate = 2;
  810.             while (wstate != 0) {
  811.                 if ( ( ( XmitByte < 0x20 ) && ( lap->PPP_activeACM & ( 1L << XmitByte ) ) ) ||
  812.                 ( XmitByte == PPP_FLAG ) || ( XmitByte == PPP_ESCAPE ) ) {
  813.                     *xbufp++ = PPP_ESCAPE;
  814.                     XmitByte ^= 0x20;
  815.                 }
  816.                 *xbufp++ = (Byte) XmitByte;
  817.                 XmitByte = lap->XmitFCS >> 8;
  818.                 wstate--;
  819.             }
  820.  
  821.             /* do closing flag */
  822.  
  823.             *xbufp++ = PPP_FLAG;
  824.             xmitfifo(lap, xbufp - lap->xbuf);  /* send it along */
  825.             
  826.         } else if (wstate == s_Finish || wstate == s_Loopback) {
  827.         /*
  828.         *  If the buffer just sent was an IP datagram, let the
  829.         *  IP layer know we finished the write.
  830.         */
  831.             pb = lap->active;        /* store pointer to current iopb */
  832.             lap->active = nil;        /* make current nil */
  833.             lap->write_state = s_Idle;    /* Idle state */
  834.             if ( pb->ipbuf != nil) {
  835.                 if (wstate == s_Loopback)
  836.                     ProcFrame(lap, pb->bufptr);    /* loopback packet around */
  837.                 pb->ipbuf->iop.ioResult = noErr;    /* i/o is complete */
  838.                 IOfinish(lap, pb); /* call completion routine */
  839.             } else
  840.                 /*  not an IP packet, just put iopb on free queue */
  841.                 Enqueue((QElemPtr) pb, (QHdrPtr) &lap->pppbq);    /* put on free Q */
  842.         } else if (wstate == s_Init)
  843.             break;
  844.         else  {
  845.             lap->OutError++;
  846.             PPP_DEBUG_CHECKS("\pPPP Tx: bad state");
  847.         }
  848.     }
  849. }
  850.